package server

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"strings"
)

const FixedAttrNum int = 5 //固定属性个数

// AttrArr implements sort.Interface for []map[string]interface{}
type AttrArr []map[string]interface{}

func (a AttrArr) Len() int      { return len(a) }
func (a AttrArr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a AttrArr) Less(i, j int) bool {
	iVal, _ := a[i]["priority"].(int64)
	jVal, _ := a[j]["priority"].(int64)
	return iVal < jVal
}

//获取一个人的所有属性
func api_get_person_attrs(tx *sql.Tx, target_person int64) *ReturnStruct {
	rows, err := tx.Query("select id, attr_name, 0 as fix, priority from tb_person_attr where person_id = ? order by priority", target_person)
	if err != nil {
		return DBErrReturn("查找自定义属性异常", err)
	}
	result, err := SelectResultFromRows(rows)
	if err != nil {
		return DBErrReturn("解析自定义属性异常", err)
	}

	//遍历自定义属性的所有priority, 找出空缺的位置，给固定属性填进去
	priorities, err := GetIntColumnFromResult(result, "priority")
	if err != nil {
		return DBErrReturn("解析Priority属性失败", err)
	}
	fixedpri := make([]int64, 0)
	var currIndex int64 = 1 //当前计数
	for i := 0; i < len(priorities); {
		val := priorities[i]
		if val > currIndex {
			fixedpri = append(fixedpri, currIndex)
			if len(fixedpri) == FixedAttrNum {
				//取够固定属性就可以了
				break
			}
			currIndex++
		} else if val == currIndex {
			currIndex++
			i++
		} else {
			return SvrErrReturn("查询到的priority异常！")
		}
	}
	for ; len(fixedpri) < FixedAttrNum; currIndex++ {
		fixedpri = append(fixedpri, currIndex)
	}

	//在自定义属性之前加入固定属性，固定属性的编辑方式可能不同。
	fixAttrNames := [FixedAttrNum]string{
		"姓名",
		"性别",
		"昵称",
		"生日",
		"电话",
	}
	for i := 0; i < FixedAttrNum; i++ {
		fixAttr := map[string]interface{}{
			"id":        -(i + 1),
			"attr_name": fixAttrNames[i],
			"fix":       1,
			"priority":  fixedpri[i],
		}
		result = append(result, fixAttr)
	}

	//根据权重由小到大排序
	sort.Sort(AttrArr(result))

	return SuccRet(result)
}

//获取所有属性，含固定属性和自定义属性
func get_person_attrs(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type InputInfo struct {
		Family       int64 `json:"family"`
		TargetPerson int64 `json:"target_person"`
	}
	var input InputInfo
	err := json.Unmarshal([]byte(jsonData), &input)
	if err != nil {
		return FailRet(CodeParamError, err)
	}

	//校验当前人
	isContains, err := api_family_contain_person(tx, input.Family, []int64{person_id, input.TargetPerson})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	result := api_get_person_attrs(tx, input.TargetPerson)
	return result
}

//设置所有属性，含固定属性和自定义属性，属性名，排序 一起保存。需要前端给出请求之前的自定义属性列表，用来避免多端修改引起的不一致性。
//已有属性id大于0， 固定属性id依次取：-1，-2，-3... ， 新增属性id从-10000开始取。 priority仅后端排序用，对于前端来说没用。
func set_person_attrs(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {

	type AttrInfo struct {
		Id       int    `json:"id"`
		Name     string `json:"attr_name"`
		Fix      int    `json:"fix"`
		Priority int
	}
	type Param struct {
		Family       int64      `json:"family"`
		TargetPerson int64      `json:"target_person"`
		NewAttrs     []AttrInfo `json:"new_attrs"`
		OldAttrs     []int      `json:"old_attrs"` //编辑之前的所有自定义属性id
	}

	var param Param
	err := json.Unmarshal([]byte(jsonData), &param)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := param.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, param.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	//先验证编辑前的属性是否一致
	var count int
	err = tx.QueryRow("select count(*) from tb_person_attr where person_id = ?", target_person).Scan(&count)
	if err != nil {
		return DBErrReturn("查询属性个数失败", err)
	}
	if len(param.OldAttrs) != count {
		return SvrErrReturn("属性已更新，请刷新后再修改")
	}
	if len(param.OldAttrs) > 0 {
		sql := fmt.Sprintf("select count(*) from tb_person_attr where person_id = ? and id in (%s)", strings.Join(ArrIntToArrStr(param.OldAttrs), ","))
		err = tx.QueryRow(sql, target_person).Scan(&count)
		if err != nil {
			return DBErrReturn("查询特定属性个数失败", err)
		}
		if count != len(param.OldAttrs) {
			return SvrErrReturn("特定属性已更新，请刷新后再修改")
		}
	}

	//开始更新新属性
	Attrs := param.NewAttrs
	if len(Attrs) > 255 {
		return ParamErrReturn("属性总数不能超过255")
	}

	//验证固定属性
	existIds := make([]int, 0) //所有存在的id, 如果是新增属性，Id为0
	fixnum := 0
	for i := 0; i < len(Attrs); i++ {
		if Attrs[i].Fix == 1 {
			fixnum++
		} else if Attrs[i].Id > 0 {
			existIds = append(existIds, Attrs[i].Id)
		}
		//更新Priority参数
		Attrs[i].Priority = i + 1
	}
	if fixnum != FixedAttrNum {
		return FailRet(CodeParamError, "固定属性个数错误")
	}

	//验证已有自定义属性
	if len(existIds) > 0 {
		sql := fmt.Sprintf("select count(*) from tb_person_attr where person_id = ? and id in (%s)", strings.Join(ArrIntToArrStr(existIds), ","))
		err = tx.QueryRow(sql, target_person).Scan(&count)
		if err != nil {
			return DBErrReturn("请求已有属性发生错误", err)
		}
		if count != len(existIds) {
			return SvrErrReturn("参数中的已有属性有异常或重复数据")
		}
	}

	//删除自定义属性
	if len(existIds) > 0 {
		sql := fmt.Sprintf("delete from tb_person_attr where person_id = ? and id not in (%s)", strings.Join(ArrIntToArrStr(existIds), ","))
		_, err = tx.Exec(sql, target_person)
		if err != nil {
			return DBErrReturn("删除自定义属性失败", err)
		}
	} else {
		_, err = tx.Exec("delete from tb_person_attr where person_id = ?", target_person)
		if err != nil {
			return DBErrReturn("整体删除自定义属性失败", err)
		}
	}

	//更新自定义属性
	for i := 0; i < len(Attrs); i++ {
		//更新已有属性
		if Attrs[i].Fix == 0 && Attrs[i].Id > 0 {
			_, err = tx.Exec("update tb_person_attr set attr_name = ?, priority = ? where id = ?", Attrs[i].Name, Attrs[i].Priority, Attrs[i].Id)
			if err != nil {
				return DBErrReturn("更新已有属性失败", err)
			}
		}

		//插入新增属性
		if Attrs[i].Fix == 0 && Attrs[i].Id <= -10000 {
			result, err := tx.Exec("insert into tb_person_attr(person_id, attr_name, priority) values (?, ?, ?)", target_person, Attrs[i].Name, Attrs[i].Priority)
			if err != nil {
				return DBErrReturn("插入已有属性错误", err)
			}
			count, _ := result.RowsAffected()
			if count != 1 {
				return DBErrReturn("插入已有属性失败", err)
			}
		}
	}

	//修改成功,返回所有属性
	result := api_get_person_attrs(tx, target_person)
	return result
}

func api_get_person_vals(tx *sql.Tx, family int64, person_id int64, target_person int64) *ReturnStruct {
	//查找到所有属性
	attr_result := api_get_person_attrs(tx, target_person)
	if attr_result.is_fail() {
		return attr_result
	}
	attrs := attr_result.Data
	attrs_arr, _ := attrs.([]map[string]interface{})

	//再查找到所有值
	rows, err := tx.Query("select id, attr_val from tb_person_attr where person_id = ?", target_person)
	if err != nil {
		return DBErrReturn("查找自定义属性异常", err)
	}
	attr_rows, err := SelectResultFromRows(rows)
	if err != nil {
		return DBErrReturn("解析自定义属性异常", err)
	}
	attr_value_map := make(map[int64]string) //id -> value
	for i := 0; i < len(attr_rows); i++ {
		id, _ := attr_rows[i]["id"].(int64)
		val, _ := attr_rows[i]["attr_val"].(string)
		attr_value_map[id] = val
	}
	var fix_name string
	var fix_nick string
	var fix_sex int
	var fix_birthday string
	var fix_phone string
	err = tx.QueryRow("select a.name, ifnull(b.nick, '') as nick, a.sex, a.birthday, a.phone from tb_person a left join tb_nicks b on b.family = ? and b.main_person = ? and b.call_person = a.id where a.id = ?", family, person_id, target_person).Scan(&fix_name, &fix_nick, &fix_sex, &fix_birthday, &fix_phone)
	if err != nil {
		return DBErrReturn("查询固定属性失败", err)
	}

	//将值添加到属性上, 这样就保持了属性的顺序
	for i := 0; i < len(attrs_arr); i++ {
		id, _ := attrs_arr[i]["id"].(int64)
		attr_name, _ := attrs_arr[i]["attr_name"].(string)

		if id > 0 {
			//自定义属性
			value, ok := attr_value_map[id]
			if ok {
				attrs_arr[i]["value"] = value
			} else {
				attrs_arr[i]["value"] = ""
			}
		} else {
			//固定属性
			switch attr_name {
			case "姓名":
				attrs_arr[i]["value"] = fix_name
			case "性别":
				attrs_arr[i]["value"] = strconv.FormatInt(int64(fix_sex), 10)
			case "昵称":
				attrs_arr[i]["value"] = fix_nick
			case "生日":
				attrs_arr[i]["value"] = fix_birthday
			case "电话":
				attrs_arr[i]["value"] = fix_phone
			default:
				panic("存在遗漏的固定属性")
			}
		}
	}

	return SuccRet(attrs_arr)
}

//获取所有属性值
func get_person_vals(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type InputInfo struct {
		Family       int64 `json:"family"`
		TargetPerson int64 `json:"target_person"`
	}
	var input InputInfo
	err := json.Unmarshal([]byte(jsonData), &input)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := input.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, input.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	vals_ret := api_get_person_vals(tx, input.Family, person_id, target_person)
	if vals_ret.is_fail() {
		return vals_ret
	}

	type Result struct {
		Vals             interface{} `json:"vals"`          //属性列表
		CreatePersonId   int64       `json:"create_person"` //添加者
		CreatePersonName string      `json:"create_person_name"`
	}
	var result Result
	result.Vals = vals_ret.Data
	err = tx.QueryRow("select b.id, b.name from tb_family_member a join tb_person b on a.family_id = ? and a.person_id = ? and a.person_id = b.id", input.Family, input.TargetPerson).Scan(&result.CreatePersonId, &result.CreatePersonName)
	if err != nil {
		return DBErrReturn("查询添加者", err)
	}
	return SuccRet(result)
}

//设置所有属性值
func set_person_vals(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type AttrValue struct {
		Id    int    `json:"id"`
		Name  string `json:"attr_name"`
		Fix   int    `json:"fix"`
		Value string `json:"value"`
	}
	type Param struct {
		Family       int64       `json:"family"`
		TargetPerson int64       `json:"target_person"`
		Values       []AttrValue `json:"values"`
	}
	var param Param
	err := json.Unmarshal([]byte(jsonData), &param)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := param.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, param.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	//更新
	for i := 0; i < len(param.Values); i++ {
		id := param.Values[i].Id
		name := param.Values[i].Name
		value := param.Values[i].Value
		if id > 0 {
			//自定义属性
			_, err = tx.Exec("update tb_person_attr set attr_val = ? where id = ?", value, id)
			if err != nil {
				return DBErrReturn("更新自定义属性失败", err)
			}
		} else {
			//固定属性
			person_set_sqls := make([]string, 0)
			switch name {
			case "姓名":
				person_set_sqls = append(person_set_sqls, fmt.Sprintf("name = '%s'", value))
			//不支持修改性别
			//case "性别":
			//	sex, err := strconv.ParseInt(value, 10, 8)
			//	if err != nil {
			//		return ParamErrReturn("性别参数错误")
			//	}
			//	person_set_sqls = append(person_set_sqls, fmt.Sprintf("sex = %d", sex))
			case "生日":
				person_set_sqls = append(person_set_sqls, fmt.Sprintf("birthday = '%s'", value))
			case "电话":
				person_set_sqls = append(person_set_sqls, fmt.Sprintf("phone = '%s'", value))
			case "昵称":
				value = strings.Trim(value, " ")
				if len(value) == 0 {
					_, err = tx.Exec("delete from tb_nicks where family = ? and main_person = ? and call_person = ?", param.Family, person_id, target_person)
					if err != nil {
						return DBErrReturn("删除昵称失败", err)
					}
				} else {
					var count int64
					err = tx.QueryRow("select count(*) from tb_nicks where family = ? and main_person = ? and call_person = ?", param.Family, person_id, target_person).Scan(&count)
					if err != nil {
						return DBErrReturn("查询昵称失败", err)
					}
					if 0 == count {
						result, err := tx.Exec("insert into tb_nicks(family, main_person, call_person, nick) values (?,?,?,?)", param.Family, person_id, target_person, value)
						if err != nil {
							return DBErrReturn("插入昵称失败", err)
						}
						count, _ = result.RowsAffected()
						if 0 == count {
							return SvrErrReturn("插入昵称异常")
						}
					} else {
						_, err = tx.Exec("update tb_nicks set nick = ? where family = ? and main_person = ? and call_person = ?", value, param.Family, person_id, target_person)
						if err != nil {
							return DBErrReturn("更新昵称失败", err)
						}
					}
				}
			default:
				panic("存在遗漏的固定属性")
			}

			if len(person_set_sqls) > 0 {
				sql := fmt.Sprintf("update tb_person set %s where id = ?", strings.Join(person_set_sqls, ","))
				_, err = tx.Exec(sql, target_person)
				if err != nil {
					return DBErrReturn("更新人员信息失败", err)
				}
			}
		}
	}

	return api_get_person_vals(tx, param.Family, person_id, target_person)
}

//增加个人图片
func add_person_pic(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type Param struct {
		Family       int64    `json:"family"`
		TargetPerson int64    `json:"target_person"`
		PicNames     []string `json:"pic_names"` //图片文件名
	}
	var param Param
	err := json.Unmarshal([]byte(jsonData), &param)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := param.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, param.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	for i := 0; i < len(param.PicNames); i++ {
		if len(param.PicNames[i]) > 0 {
			_, err := tx.Exec("insert into tb_person_pic(person_id, pic_name) values (?,?)", target_person, param.PicNames[i])
			if err != nil {
				return DBErrReturn("插入图片失败", err)
			}
		}
	}
	return SuccRet(nil)
}

//删除个人图片
func del_person_pic(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type Param struct {
		Family       int64  `json:"family"`
		TargetPerson int64  `json:"target_person"`
		PicName      string `json:"pic_name"` //图片文件名
	}
	var param Param
	err := json.Unmarshal([]byte(jsonData), &param)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := param.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, param.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	_, err = tx.Exec("delete from tb_person_pic where person_id = ? and pic_name = ?", target_person, param.PicName)
	if err != nil {
		return DBErrReturn("删除图片失败", err)
	}
	return SuccRet(nil)
}

//获取某人的相片
func get_person_pic(tx *sql.Tx, person_id int64, jsonData string) *ReturnStruct {
	type Param struct {
		Family       int64 `json:"family"`
		TargetPerson int64 `json:"target_person"`
	}
	var param Param
	err := json.Unmarshal([]byte(jsonData), &param)
	if err != nil {
		return FailRet(CodeParamError, err)
	}
	target_person := param.TargetPerson

	//校验当前人
	isContains, err := api_family_contain_person(tx, param.Family, []int64{person_id, target_person})
	if err != nil {
		return DBErrReturn("校验当前人异常", err)
	}
	if !isContains {
		return ParamErrReturn("校验当前人失败")
	}

	rows, err := tx.Query("select pic_name from tb_person_pic where person_id = ?", target_person)
	selectRows, err := SelectResultFromRows(rows)
	if err != nil {
		return DBErrReturn("解析属性异常", err)
	}
	pic_names := make([]string, 0)
	for i := 0; i < len(selectRows); i++ {
		val, _ := selectRows[i]["pic_name"]
		name, _ := val.(string)
		pic_names = append(pic_names, name)
	}
	return SuccRet(pic_names)
}
